import { Resource } from '@tomic/lib';
import { useCallback, useEffect, useRef, useState } from 'react';

// T is a generic type for value parameter, our case this will be string
export function useDebounce<T>(value: T, delay: number): T {
  // State and setters for debounced value
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  useEffect(
    () => {
      // Update debounced value after delay
      const handler = setTimeout(() => {
        setDebouncedValue(value);
      }, delay);

      // Cancel the timeout if value changes (also on delay change or unmount)
      // This is how we prevent debounced value from updating if value is changed ...
      // .. within the delay period. Timeout gets cleared and restarted.
      return () => {
        clearTimeout(handler);
      };
    },
    [value, delay], // Only re-call effect if value or delay changes
  );

  return debouncedValue;
}

export function useDebouncedSave(
  resource: Resource,
  timeout: number,
  onError?: (error: Error) => void,
): [save: () => void, savePending: boolean] {
  const timeoutId = useRef<ReturnType<typeof setTimeout>>(undefined);
  const [savePending, setSavePending] = useState(false);

  const save = useCallback(() => {
    if (timeoutId.current) {
      clearTimeout(timeoutId.current);
    }

    timeoutId.current = setTimeout(async () => {
      try {
        await resource.__internalObject.save();
        setSavePending(false);
      } catch (e) {
        if (onError) {
          onError(e);
        } else {
          throw e;
        }
      }
    }, timeout);

    setSavePending(true);
  }, [resource.__internalObject, timeout, onError]);

  return [save, savePending];
}
